using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Universe
{
    public class ConfigurationContainer
    {
        private readonly IDictionary<Type, Delegate> repository = new Dictionary<Type, Delegate>();

        public delegate T Func<T>();
        
        public void Register<TContract>(Func<TContract> function)
        {
            repository[typeof(TContract)] = function;
        }

        public T Resolve<T>()
        {
            T result;
            ResolveImpl<T>(out result);
            return result;
        }

        public T ResolveRequired<T>()
        {
            T result;
            if (!ResolveImpl(out result))
                throw new ConfigurationException("Implementation of " + typeof(T) + " is not provided");

            return result;
        }

        private bool ResolveImpl<T>(out T result)
        {
            Delegate @delegate;
            if (!repository.TryGetValue(typeof(T), out @delegate))
            {
                result = default(T);
                return false;
            }

            Func<T> func = (Func<T>) @delegate;
            result = func();
            return true;
        }
    }

    [Serializable]
    public class ConfigurationException : Exception
    {
        public ConfigurationException()
        {
        }


        public ConfigurationException(string message)
            : base(message)
        {
        }


        public ConfigurationException(string message, Exception innerException)
            : base(message, innerException)
        {
        }


        protected ConfigurationException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }
}